// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/WidgetController/OverlayWidgetController.h"

#include "AbilitySystem/AuraAbilitySystemComponent.h"
#include "AbilitySystem/AuraAttributeSet.h"
#include "DataAsset/LevelUpInfo.h"
#include "Player/AuraPlayerState.h"

void UOverlayWidgetController::BroadcastInitialValues()
{
	// Super::BroadcastInitialValues();

	const UAuraAttributeSet* AuraAttributeSet = CastChecked<UAuraAttributeSet>(AttributeSet);

	// 广播属性初始值
	OnHealthChangedDelegate.Broadcast(AuraAttributeSet->GetHealth());
	OnMaxHealthChangedDelegate.Broadcast(AuraAttributeSet->GetMaxHealth());
	OnManaChangedDelegate.Broadcast(AuraAttributeSet->GetMana());
	OnMaxManaChangedDelegate.Broadcast(AuraAttributeSet->GetMaxMana());
}

void UOverlayWidgetController::BindCallbacksToDependencies()
{
	const UAuraAttributeSet* AuraAttributeSet = CastChecked<UAuraAttributeSet>(AttributeSet);
	AAuraPlayerState* AuraPlayerState = CastChecked<AAuraPlayerState>(PlayerState);

	// 绑定经验变化回调
	AuraPlayerState->OnXPChangedDelegate.AddUObject(this, &ThisClass::OnXPChanged);

	// 为属性值变化委托绑定事件,将变化值广播出去
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AuraAttributeSet->GetHealthAttribute()).AddLambda(
		[this](const FOnAttributeChangeData& AttributeChangeData)
		{
			OnHealthChangedDelegate.Broadcast(AttributeChangeData.NewValue);
		}
	);
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AuraAttributeSet->GetMaxHealthAttribute()).
	                        AddLambda(
		                        [this](const FOnAttributeChangeData& AttributeChangeData)
		                        {
			                        OnMaxHealthChangedDelegate.Broadcast(AttributeChangeData.NewValue);
		                        }
	                        );
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AuraAttributeSet->GetManaAttribute()).AddLambda(
		[this](const FOnAttributeChangeData& AttributeChangeData)
		{
			OnManaChangedDelegate.Broadcast(AttributeChangeData.NewValue);
		}
	);
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AuraAttributeSet->GetMaxManaAttribute()).AddLambda(
		[this](const FOnAttributeChangeData& AttributeChangeData)
		{
			OnMaxManaChangedDelegate.Broadcast(AttributeChangeData.NewValue);
		}
	);

	if (UAuraAbilitySystemComponent* ASC = Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent))
	{
		if (ASC->bStartupAbilitiesGiven) // 如果已经赋予了初始技能，则直接调用函数进行广播能力数据到UI
		{
			OnInitStartupAbilities(ASC);
		}
		else // 忽略网络因素是先初始化UI在初始化技能,则绑定委托
		{
			ASC->AbilityGivenDelegate.AddUObject(this, &ThisClass::OnInitStartupAbilities);
		}

		// 将符合标签的数据广播出去
		ASC->EffectAssetTagsDelegate.AddLambda(
			[this](const FGameplayTagContainer& TagContainer)
			{
				for (const FGameplayTag& Tag : TagContainer)
				{
					FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message"));
					// "A.1".MatchesTag("A") will return True, "A".MatchesTag("A.1") will return False
					if (Tag.MatchesTag(MessageTag))
					{
						const FUIWidgetRow* DataTableRow = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable, Tag);
						MessageWidgetRowDelegate.Broadcast(*DataTableRow);
					}
				}
			}
		);
	}
}

void UOverlayWidgetController::OnXPChanged(const int32 NewXP) const
{
	const AAuraPlayerState* AuraPlayerState = CastChecked<AAuraPlayerState>(PlayerState);
	ULevelUpInfo* LevelUpInfo = AuraPlayerState->LevelUpInfo;
	checkf(LevelUpInfo, TEXT("LevelUpInfo is nullptr"));

	const int32 Level = LevelUpInfo->FindLevelForXP(NewXP); // 获取当前经验值对应的等级
	const int32 MaxLevel = LevelUpInfo->LevelUpInformation.Num() - 1; // 获取最大等级

	if (Level <= MaxLevel && Level > 0)
	{
		const int32 LevelUpRequirement = LevelUpInfo->LevelUpInformation[Level].LevelUpRequirement;
		const int32 PreviousLevelUpRequirement = LevelUpInfo->LevelUpInformation[Level - 1].LevelUpRequirement;

		const float XPPercent = static_cast<float>(NewXP - PreviousLevelUpRequirement) / (
			LevelUpRequirement - PreviousLevelUpRequirement);
		
		//广播经验条比例
		OnXPChangedDelegate.Broadcast(XPPercent);
	}
}

/**
 * @brief 初始化并广播角色初始技能信息到UI界面  
 * 当技能系统组件的初始技能已赋予时，遍历所有技能，获取其信息并触发广播  
 */
void UOverlayWidgetController::OnInitStartupAbilities(UAuraAbilitySystemComponent* ASC) const
{
	// 如果初始技能未成功赋予，直接退出（通常在回调触发时已完成初始化）
	if (!ASC->bStartupAbilitiesGiven) return;

	// 创建携带技能的委托
	FForeachAbility BroadcastDelegate;
	// 携带技能的委托绑定到函数
	BroadcastDelegate.BindLambda(
		[this](FGameplayAbilitySpec& AbilitySpec)
		{
			// 通过技能标签查询完整的技能元数据信息
			FAuraAbilityInfo Info = AbilityInfo->FindAbilityInfoByTag(
				UAuraAbilitySystemComponent::GetAbilityTagFormSpec(AbilitySpec)
			);

			// 从技能规格中提取输入绑定标签并更新到信息结构
			Info.InputTag = UAuraAbilitySystemComponent::GetInputTagFormSpec(AbilitySpec);

			// 携带完整技能信息广播到UI
			AbilityInfoDelegate.Broadcast(Info);
		}
	);

	// 执行技能遍历操作,携带技能的委托广播出去
	ASC->ForeachCharacterAbilities(BroadcastDelegate);
}
